// // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
// //
// // Licensed under the Apache License, Version 2.0 (the "License");
// // you may not use this file except in compliance with the License.
// // You may obtain a copy of the License at

// //     http://www.apache.org/licenses/LICENSE-2.0
// //
// // Unless required by applicable law or agreed to in writing, software
// // distributed under the License is distributed on an "AS IS" BASIS,
// // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// // See the License for the specific language governing permissions and
// // limitations under the License.

// #include <stdint.h>
// #include <string.h>
// #include <stdbool.h>
// #include "freertos/xtensa_api.h"
// #include "freertos/FreeRTOSConfig.h"
// #include "freertos/FreeRTOS.h"
// #include "freertos/queue.h"
// #include "freertos/task.h"
// #include "esp_log.h"
// #include "spp_task.h"
// #include "esp_gap_bt_api.h"
// #include "esp_bt_device.h"
// #include "esp_spp_api.h"
// #include "esp_bt.h"
// #include "esp_bt_main.h"
// #include "esp_vfs.h"
// #include "sys/unistd.h"
// #include "esp_camera.h"
// #include "spp_task.h"
// #include "esp_gap_bt_api.h"

// #include "spp_command_process.h"

// #define ring_data_len() ((read_head + sizeof(receive_buff) - read_tail) % SPP_PROCESS_BUFF_SIZE)
// #define ring_next_index(target,n) (((n) + (target)) % SPP_PROCESS_BUFF_SIZE)
// #define ring_is_null() (read_head == read_tail)
// #define ring_is_full() (ring_next_index(read_head,1) == read_tail)
// #define ring_get_data() receive_buff[read_tail]
// #define ring_del_data() read_tail = ring_next_index(read_tail, 1)
#define ringbuf_add_data(data) do\
    {\
		receive_buff[read_head] = data;\
	    read_head = (read_head + 1) % sizeof(receive_buff);\
    }while(0);

#define ring_cpy_data(buf,len,head) do\
	{\
		for(int i=0;i<(len);i++)\
		  {\
			buf[i] = receive_buff[head];\
			head = ring_next_index(head ,1);\
		  }\
	}while(0);


// static void spp_task_task_handler(void *arg);
// static bool spp_task_send_msg(spp_task_msg_t *msg);
// static void spp_task_work_dispatched(spp_task_msg_t *msg);

// char * software_version = "V1.5.1.0-19122015";
// #define SPP_TAG "SPP_ACCEPTOR_DEMO"
// #define SPP_SERVER_NAME "SPP_SERVER"
// #define EXAMPLE_DEVICE_NAME "snapmaker_bt"

// static xQueueHandle process_data_push_queue = NULL;
// static xQueueHandle spp_task_task_queue = NULL;
// static xTaskHandle spp_task_task_handle = NULL;

// static const esp_spp_mode_t esp_spp_mode = ESP_SPP_MODE_VFS;

// static const esp_spp_sec_t sec_mask = ESP_SPP_SEC_AUTHENTICATE;
// static const esp_spp_role_t role_slave = ESP_SPP_ROLE_SLAVE;
// static uint16_t u16CurCmdLen = 0;
// #define SPP_DATA_LEN 100
// #define SPP_PROCESS_BUFF_SIZE 1024
// static uint8_t spp_data[SPP_DATA_LEN];
// // Process buffer
// static uint8_t receive_buff[SPP_PROCESS_BUFF_SIZE];
// static uint16_t read_tail;
// static uint16_t read_head;
// static uint8_t parse_buff[SPP_PROCESS_BUFF_SIZE];
// //Spp file handler
// int spp_file_handler = -1;
// //16进制打印
// void display_buffer_hex(unsigned char *buffer, unsigned size)
// {
// 	unsigned i, j, k;

// 	for (i=0; i<size; i+=16) {
// 		printf("\n  %08x  ", i);
// 		for(j=0,k=0; k<16; j++,k++) {
// 			if (i+j < size) {
// 				printf("%02x", buffer[i+j]);
// 			} else {
// 				printf("  ");
// 			}
// 			printf(" ");
// 		}
// 		printf(" ");
// 		for(j=0,k=0; k<16; j++,k++) {
// 			if (i+j < size) {
// 				if ((buffer[i+j] < 32) || (buffer[i+j] > 126)) {
// 					printf(".");
// 				} else {
// 					printf("%c", buffer[i+j]);
// 				}
// 			}
// 		}
// 	}
// 	printf("\n" );
// }

// uint16_t data_check(uint8_t opcode, uint8_t result, uint8_t *data,uint16_t len) {
// 	uint32_t checksum = 0;
// 	char *pDATA = (char *)(data);
//     checksum += ((opcode << 8) | result);
//     if (data != NULL && len > 0) {
//     	for(int i=0;i<((len)-1);i=i+2) {
//     		checksum += (pDATA[i] << 8) | pDATA[i + 1];
//         }
//     	if((len) % 2) {
//     		checksum += pDATA[(len) - 1];
//         }
//     }
// 	while(checksum > 0xffff)
// 		checksum = ((checksum >> 16) & 0xffff) + (checksum & 0xffff);
// 	checksum = ~checksum;
// 	return checksum;
// }

// /**
//   * @brief  Ssp send data
//   * @param  pBuff:The buffer of the data
//   * @param  Len:The length of the data
//   * @retval true for send success
//   */
// bool ssp_write_data(uint8_t *pBuff, uint16_t Len) {
//   int cur_byte_sent;
//   int byte_sent;
//   int byte_to_send;
//   int send_index;
//   uint32_t total_send;

//   if(spp_file_handler < 0)
//     return false;

//   total_send = Len;
//   byte_sent = 0;
//   send_index = 0;
//   while(Len > 0) {
//     if(Len > SPP_PACK_MAX_SIZE)
//       byte_to_send = SPP_PACK_MAX_SIZE;
//     else
//       byte_to_send = Len;
//     do {
//       cur_byte_sent = write (spp_file_handler, &pBuff[send_index], byte_to_send);
//       if(cur_byte_sent == byte_to_send) {
//         byte_sent += cur_byte_sent;
//         break;
//       }
//       vTaskDelay( 20 / portTICK_RATE_MS );
//     }while(1);

//     Len = Len - byte_to_send;
//     send_index = send_index + byte_to_send;
//   }
//   //ESP_LOGI(SPP_TAG, "Send Len = %d", byte_sent);
//   return (byte_sent == total_send)?true:false;
// }

// /**
//   * @brief  Spp Data process
//   * @retval None
//   */
// void ssp_command_process(uint8_t * parse_buff, uint8_t send_port)
// {
//     int len;
//     uint8_t eventId;
//     len = ((uint16_t)parse_buff[2] << 8) | parse_buff[3];
//     eventId = parse_buff[8];
//     ESP_LOGI(SPP_TAG, "cmd = %d, opcode = %d, len = %d", eventId, parse_buff[9], len);
//     set_send_port(send_port);
//     switch(eventId) {
//         //查询软件版本号
//         case M_REPORT_VERSIONS:
//             bt_sendprotocoldata(S_REPORT_VERSIONS, 0, (uint8_t *)software_version, strlen(software_version)+1);
//             break;
//         case M_CAMERA_GET_AWB:
//             Cmd_CameraGetAwbStatu();
//             break;
//         case M_CAMERA_SET_AWB:
//             Cmd_CameraSetAWB(parse_buff[10]);
//             break;
//         //设置相机曝光时间
//         case M_CAMERA_SET_ACE:
//             Cmd_CameraSetAEC((parse_buff[10] << 8) | parse_buff[11]);
//             break;
//         // 设置图像大小
//         case M_CAMERA_SET_IMG_SIZE:
//             Cmd_CameraSetImgSize(parse_buff[10]);
//             break;
//         // 设置图像质量
//         case M_CAMERA_SET_QUALITY:
//             Cmd_CameraSetQuality(parse_buff[10]);
//             break;

//         // Take a image
//         case M_CAMERA_GET_IMG:
//             Cmd_ReportImg(&parse_buff[8], len);
//             break;
//         case M_UPDATE_MOUDLE:
//             Cmd_Update(&parse_buff[8], len);
//             break;
//         case M_SET_BT_NAME:
//             set_bt_name(&parse_buff[10], len - 2);
//             if (esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE) == ESP_OK){  // 可被发现
//                 ESP_LOGI(SPP_TAG, "Set bt name success");
//             } else {
//                 ESP_LOGE(SPP_TAG, "Set bt name fail");
//             }
//             break;
//         case M_REPORT_BT_NAME:
//             report_bt_name();
//             break;
//         case M_REPORT_BT_MAC:
//             report_bt_mac();
//             break;
//         case M_SET_CAMERA_LIGHT:
//             Cmd_CameraSetLight(&parse_buff[8], len);
//             break;
//         case M_REPORT_CAMERA_LIGHT:
//             Cmd_CameraReportLight(&parse_buff[8], len);
//             break;
//         case M_REPORT_CAMERA_STATU:
//             Cmd_CameraReportStatu();
//             break;

//     }
// }
// ERR_E spp_get_cmd(uint8_t u8Data, uint8_t * parse_buff, uint16_t * buf_index) {
//     uint16_t u16CurCmdLen = *buf_index;
//     uint16_t u16DataLen;
//     uint16_t u16Check;
//     ERR_E ret = E_DOING;

//     if (u16CurCmdLen == 0 && u8Data == 0xAA) {
//         parse_buff[u16CurCmdLen++] = u8Data;
//         ret = E_DOING;
//     } else if (u16CurCmdLen == 1 && u8Data != 0x55) {
//         u16CurCmdLen = 0;
//         ret = E_DOING;
//     } else if (u16CurCmdLen > 0) {
//         parse_buff[u16CurCmdLen++] = u8Data;
//         if (u16CurCmdLen == 6) {
//             if ((uint8_t)(parse_buff[2] ^ parse_buff[3]) != parse_buff[5]) {
//                 u16CurCmdLen = 0;
//                 ret = E_FIND_NONE;
//             }
//         } else if(u16CurCmdLen > 1) {
//             ret = E_TRUE;
//             u16CurCmdLen = 0;
//             // u16DataLen = (parse_buff[2] << 8) | parse_buff[3];
//             // if (u16DataLen + sizeof(SendPackHead_S) == u16CurCmdLen) {
//             //     u16CurCmdLen = 0;

//             //     u16Check = data_check(parse_buff[8], parse_buff[9], &parse_buff[10], u16DataLen - 2);
//             //     if (u16Check == ((parse_buff[6] << 8) | parse_buff[7])) {
//             //         ret = E_TRUE;
//             //     } else {
//             //         ESP_LOGE(SPP_TAG, "data len:%d,check fail:%.2x", u16DataLen + sizeof(SendPackHead_S), u16Check);
//             //         display_buffer_hex((unsigned char *)parse_buff, u16DataLen + sizeof(SendPackHead_S));
//             //         bt_sendprotocoldata(S_RECV_FAIL, OPCODE_FAIL, NULL, 0);
//             //         ret = E_FALSE;
//             //     }
//             // }
//         }
//     }
//     *buf_index = u16CurCmdLen;
//     return ret;
// }


// /**
//   * @brief  Spp Data parse
//   * @retval None
//   */
// void ssp_data_thread(void *args) {
//     int len;
//     while(1) {
//         xQueueReceive(process_data_push_queue, &len, 500 / portTICK_RATE_MS);
//         while (!ring_is_null()) {
//             uint8_t u8Data = ring_get_data();
//             ring_del_data();
//             set_send_port(BT_PORT_SEND);
//             if (spp_get_cmd(u8Data, parse_buff, &u16CurCmdLen) == E_TRUE) {
//                 ssp_command_process(parse_buff, BT_PORT_SEND);
//             }
//         }
//     }
// }

// /**
//   * @brief  Push receive data to the process buffer
//   * @param  pBuff:The buffer of the receive data
//   * @param  len:The length of the receive data
//   * @retval The length have been pushed
//   */
// static uint8_t push_read_data(uint8_t *pBuff, int len) {
//   for (int i = 0; i < len; i++) {
//       if (!ring_is_full()) {
//           ringbuf_add_data(pBuff[i]);
//       } else {
//           ESP_LOGE(SPP_TAG, "recv buf fall");
//           return i;
//       }
//   }
//   return len;
// }

// static void spp_read_handle(void * param)
// {
//     int push_size;
//     int size = 0;
//     int fd = (int)param;
//     do {
//         size = read (fd, spp_data, SPP_DATA_LEN);
//         if (size == -1) {
//             break;
//         }

//         if (size == 0) {
//             /*read fail due to there is no data, retry after 1s*/
//             vTaskDelay(300 / portTICK_PERIOD_MS);
//         }
//         else if(size > 0) {
//           push_size = push_read_data(spp_data, size);
//           xQueueSend(process_data_push_queue, (void*)&push_size, 10 / portTICK_RATE_MS);
//         }
//     } while (1);
//     spp_wr_task_shut_down();
// }

// static void esp_spp_cb(uint16_t e, void *p)
// {
//     esp_spp_cb_event_t event = e;
//     esp_spp_cb_param_t *param = p;

//     switch (event) {
//     case ESP_SPP_INIT_EVT:
//         ESP_LOGI(SPP_TAG, "ESP_SPP_INIT_EVT，name:%s",EXAMPLE_DEVICE_NAME);
//         esp_bt_dev_set_device_name(EXAMPLE_DEVICE_NAME);
//         esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE);  // 能连接但不能被发现
//         esp_spp_start_srv(sec_mask,role_slave, 0, SPP_SERVER_NAME);
//         break;
//     case ESP_SPP_DISCOVERY_COMP_EVT:
//         ESP_LOGI(SPP_TAG, "ESP_SPP_DISCOVERY_COMP_EVT");
//         break;
//     case ESP_SPP_OPEN_EVT:
//         ESP_LOGI(SPP_TAG, "ESP_SPP_OPEN_EVT");
//         break;
//     case ESP_SPP_CLOSE_EVT:
//         ESP_LOGI(SPP_TAG, "ESP_SPP_CLOSE_EVT");
//         spp_file_handler = -1;
//         break;
//     case ESP_SPP_START_EVT:
//         ESP_LOGI(SPP_TAG, "ESP_SPP_START_EVT");
//         break;
//     case ESP_SPP_CL_INIT_EVT:
//         ESP_LOGI(SPP_TAG, "ESP_SPP_CL_INIT_EVT");
//         break;
//     case ESP_SPP_SRV_OPEN_EVT:
//         ESP_LOGI(SPP_TAG, "ESP_SPP_SRV_OPEN_EVT");
//         spp_file_handler = param->srv_open.fd;
//         spp_wr_task_start_up(spp_read_handle, param->srv_open.fd);
//         break;
//     default:
//         break;
//     }
// }

// static void esp_spp_stack_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
// {
//     spp_task_work_dispatch(esp_spp_cb, event, param, sizeof(esp_spp_cb_param_t), NULL);
// }

// void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
// {
//     switch (event) {
//     case ESP_BT_GAP_AUTH_CMPL_EVT:{
//         if (param->auth_cmpl.stat == ESP_BT_STATUS_SUCCESS) {
//             ESP_LOGI(SPP_TAG, "authentication success: %s", param->auth_cmpl.device_name);
//             esp_log_buffer_hex(SPP_TAG, param->auth_cmpl.bda, ESP_BD_ADDR_LEN);
//         } else {
//             ESP_LOGE(SPP_TAG, "authentication failed, status:%d", param->auth_cmpl.stat);
//         }
//         break;
//     }
//     case ESP_BT_GAP_PIN_REQ_EVT:{
//         ESP_LOGI(SPP_TAG, "ESP_BT_GAP_PIN_REQ_EVT min_16_digit:%d", param->pin_req.min_16_digit);
//         if (param->pin_req.min_16_digit) {
//             ESP_LOGI(SPP_TAG, "Input pin code: 0000 0000 0000 0000");
//             esp_bt_pin_code_t pin_code = {0};
//             esp_bt_gap_pin_reply(param->pin_req.bda, true, 16, pin_code);
//         } else {
//             ESP_LOGI(SPP_TAG, "Input pin code: 1234");
//             esp_bt_pin_code_t pin_code;
//             pin_code[0] = '1';
//             pin_code[1] = '2';
//             pin_code[2] = '3';
//             pin_code[3] = '4';
//             esp_bt_gap_pin_reply(param->pin_req.bda, true, 4, pin_code);
//         }
//         break;
//     }

// #if (CONFIG_BT_SSP_ENABLED == true)
//     case ESP_BT_GAP_CFM_REQ_EVT:
//         ESP_LOGI(SPP_TAG, "ESP_BT_GAP_CFM_REQ_EVT Please compare the numeric value: %d", param->cfm_req.num_val);
//         esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, true);
//         break;
//     case ESP_BT_GAP_KEY_NOTIF_EVT:
//         ESP_LOGI(SPP_TAG, "ESP_BT_GAP_KEY_NOTIF_EVT passkey:%d", param->key_notif.passkey);
//         break;
//     case ESP_BT_GAP_KEY_REQ_EVT:
//         ESP_LOGI(SPP_TAG, "ESP_BT_GAP_KEY_REQ_EVT Please enter passkey!");
//         break;
// #endif

//     default: {
//         ESP_LOGI(SPP_TAG, "event: %d", event);
//         break;
//     }
//     }
//     return;
// }

// void btc_config_clear(void);

// void spp_clean_config() {
//     int dev_num = esp_bt_gap_get_bond_device_num();
//     ESP_LOGI(SPP_TAG, "spp device count - %d", dev_num);
//     if (dev_num > 1) {
//         ESP_LOGE(SPP_TAG, "spp device clean count - %d", dev_num);
//         btc_config_clear();
//     }
// }

// bool init_bt_spp(void) {
//   //esp_err_t ret;

//   ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_BLE));

//   esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
//   if (esp_bt_controller_init(&bt_cfg) != ESP_OK) {
//     ESP_LOGE(SPP_TAG, "%s initialize controller failed", __func__);
//     return false;
//   }

//   if (esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT) != ESP_OK) {
//     ESP_LOGE(SPP_TAG, "%s enable controller failed", __func__);
//     return false;
//   }

//   if (esp_bluedroid_init() != ESP_OK) {
//     ESP_LOGE(SPP_TAG, "%s initialize bluedroid failed", __func__);
//     return false;
//   }

//   if (esp_bluedroid_enable() != ESP_OK) {
//     ESP_LOGE(SPP_TAG, "%s enable bluedroid failed", __func__);
//     return false;
//   }

//   spp_clean_config();

//   if (esp_bt_gap_register_callback(esp_bt_gap_cb) != ESP_OK) {
//     //ESP_LOGE(SPP_TAG, "%s gap register failed: %s\n", __func__, esp_err_to_name(ret));
//     return false;
//   }

//   if (esp_spp_register_callback(esp_spp_stack_cb) != ESP_OK) {
//     ESP_LOGE(SPP_TAG, "%s spp register failed", __func__);
//     return false;
//   }
//   esp_spp_vfs_register();
//   spp_task_task_start_up();

//   if (esp_spp_init(esp_spp_mode) != ESP_OK) {
//     ESP_LOGE(SPP_TAG, "%s spp init failed", __func__);
//     return false;
//   }

//   #if (CONFIG_BT_SSP_ENABLED == true)
//     /* Set default parameters for Secure Simple Pairing */
//     esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE;
//     esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_IO;
//     esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
//   #endif

//   /*
//    * Set default parameters for Legacy Pairing
//    * Use variable pin, input pin code when pairing
//    */
//   esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_VARIABLE;
//   esp_bt_pin_code_t pin_code;
//   esp_bt_gap_set_pin(pin_type, 0, pin_code);

//   read_head = read_tail = 0;
//   process_data_push_queue = xQueueCreate(1, sizeof(int));
//   xTaskCreate(ssp_data_thread, "ssp_data_process_thread", 4096, NULL, 10, NULL);

//   return true;
// }

// bool spp_task_work_dispatch(spp_task_cb_t p_cback, uint16_t event, void *p_params, int param_len, spp_task_copy_cb_t p_copy_cback)
// {
//     ESP_LOGI(SPP_TAG, "dispatch");
//     ESP_LOGD(SPP_TASK_TAG, "%s event 0x%x, param len %d", __func__, event, param_len);

//     spp_task_msg_t msg;
//     memset(&msg, 0, sizeof(spp_task_msg_t));

//     msg.sig = SPP_TASK_SIG_WORK_DISPATCH;
//     msg.event = event;
//     msg.cb = p_cback;

//     if (param_len == 0) {
//         return spp_task_send_msg(&msg);
//     } else if (p_params && param_len > 0) {
//         if ((msg.param = malloc(param_len)) != NULL) {
//             memcpy(msg.param, p_params, param_len);
//             /* check if caller has provided a copy callback to do the deep copy */
//             if (p_copy_cback) {
//                 p_copy_cback(&msg, msg.param, p_params);
//             }
//             return spp_task_send_msg(&msg);
//         }
//     }

//     return false;
// }

// static bool spp_task_send_msg(spp_task_msg_t *msg)
// {
//     if (msg == NULL) {
//         return false;
//     }

//     if (xQueueSend(spp_task_task_queue, msg, 10 / portTICK_RATE_MS) != pdTRUE) {
//         ESP_LOGE(SPP_TASK_TAG, "%s xQueue send failed", __func__);
//         return false;
//     }
//     return true;
// }

// static void spp_task_work_dispatched(spp_task_msg_t *msg)
// {
//     if (msg->cb) {
//         msg->cb(msg->event, msg->param);
//     }
// }

// static void spp_task_task_handler(void *arg)
// {
//     spp_task_msg_t msg;
//     for (;;) {
//         if (pdTRUE == xQueueReceive(spp_task_task_queue, &msg, (portTickType)portMAX_DELAY)) {
//             ESP_LOGD(SPP_TASK_TAG, "%s, sig 0x%x, 0x%x", __func__, msg.sig, msg.event);
//             switch (msg.sig) {
//             case SPP_TASK_SIG_WORK_DISPATCH:
//                 spp_task_work_dispatched(&msg);
//                 break;
//             default:
//                 ESP_LOGW(SPP_TASK_TAG, "%s, unhandled sig: %d", __func__, msg.sig);
//                 break;
//             }

//             if (msg.param) {
//                 free(msg.param);
//             }
//         }
//     }
// }

// void spp_task_task_start_up(void)
// {
//     spp_task_task_queue = xQueueCreate(10, sizeof(spp_task_msg_t));
//     xTaskCreate(spp_task_task_handler, "SPPAppT", 2048, NULL, 10, spp_task_task_handle);
//     return;
// }

// void spp_task_task_shut_down(void)
// {
//     if (spp_task_task_handle) {
//         vTaskDelete(spp_task_task_handle);
//         spp_task_task_handle = NULL;
//     }
//     if (spp_task_task_queue) {
//         vQueueDelete(spp_task_task_queue);
//         spp_task_task_queue = NULL;
//     }
// }

// void spp_wr_task_start_up(spp_wr_task_cb_t p_cback, int fd)
// {
//     xTaskCreate(p_cback, "write_read", 2048, (void *)fd, 5, NULL);
// }

// void spp_wr_task_shut_down(void)
// {
//     vTaskDelete(NULL);
// }
